home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xarchie-2.0.9 / query.c < prev    next >
C/C++ Source or Header  |  1995-06-18  |  13KB  |  441 lines

  1. /*
  2.  * query.c : Programmatic Prospero interface to Archie
  3.  *
  4.  * Copyright (c) 1991 by the University of Washington
  5.  *
  6.  * For copying and distribution information, please see the file
  7.  * <copyright.h>.
  8.  *
  9.  * Originally part of the Prospero Archie client by Clifford 
  10.  * Neuman (bcn@isi.edu).  Modifications, addition of programmatic interface,
  11.  * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) 
  12.  * and Brendan Kehoe (brendan@cs.widener.edu).
  13.  *
  14.  * v2.0   - 04/23/93 (gf)  - for xarchie 2.0 - and now we part company...
  15.  * v1.3.2 - bpk - for Archie client 1.3.2
  16.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  17.  * v1.1.3 - 08/30/91 (bpk) - cast index()
  18.  * v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink)
  19.  * v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does
  20.  */
  21. #include <copyright.h>
  22. #include <stdio.h>
  23. #include <pfs.h>
  24. #include <perrno.h>
  25. #include <archie.h>
  26.  
  27. #include "config.h"
  28. #ifdef TM_IN_SYS_TIME
  29. # include <sys/time.h>
  30. #else
  31. # include <time.h>
  32. #endif
  33. #include "stringdefs.h"
  34. #include "xtypes.h"
  35. #include "db.h"
  36. #include "appres.h"
  37. #include "browser.h"
  38. #include "alert.h"
  39. #include "status.h"
  40. #include "debug.h"
  41. extern DbEntry *db;
  42.  
  43. /* These are in dirsend.c */
  44. extern int client_dirsrv_timeout,client_dirsrv_retry,rdgram_priority;
  45.  
  46. /* Functions defined here: */
  47. void queryItemAndParse(),queryHostAndParse(),queryLocationAndParse();
  48. VLINK stringQuery();
  49. int parseArchieQueryResults(), parseStringQueryResults();
  50. int handleProsperoErrors();
  51.  
  52. static void doQueryAndParse();
  53. static void parseHostAndFilename(), parseAttributes();
  54.  
  55. /* Data defined here */
  56. int pfs_debug;
  57.  
  58. /*    -    -    -    -    -    -    -    -    */
  59. /*
  60.  * Main function to call to process a query from the user.
  61.  */
  62. void
  63. queryItemAndParse(query)
  64. char *query;
  65. {
  66.     char qstring[MAX_VPATH];
  67.  
  68.     DEBUG1("queryItemAndParse: \"%s\"\n",query);
  69.     sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
  70.         appResources.maxHits,appResources.offset,appResources.searchType,
  71.         query);
  72.     doQueryAndParse(qstring);
  73.     DEBUG0("queryItemAndParse: done\n");
  74. }
  75.  
  76. /*
  77.  * Main function to open a host specified by the user.
  78.  */
  79. void
  80. queryHostAndParse(hostname)
  81. char *hostname;
  82. {
  83.     char qstring[MAX_VPATH];
  84.  
  85.     DEBUG1("queryHostAndParse: \"%s\"\n",hostname);
  86.     sprintf(qstring,"ARCHIE/HOST/%s",hostname);
  87.     doQueryAndParse(qstring);
  88.     DEBUG0("queryHostAndParse: done\n");
  89. }
  90.  
  91. /*
  92.  * Main function to open a host specified by the user.
  93.  */
  94. void
  95. queryLocationAndParse(hostname,location)
  96. char *hostname,*location;
  97. {
  98.     char qstring[MAX_VPATH];
  99.  
  100.     DEBUG2("queryLocationAndParse: \"%s:%s\"\n",hostname,location);
  101.     sprintf(qstring,"ARCHIE/HOST/%s%s",hostname,location);
  102.     doQueryAndParse(qstring);
  103.     DEBUG0("queryLocationAndParse: done\n");
  104. }
  105.  
  106. /*
  107.  * Used by both query functions to send the string to Archie and interpret
  108.  * the results into the browser.
  109.  */
  110. static void
  111. doQueryAndParse(str)
  112. char *str;
  113. {
  114.     VLINK links;
  115.     int num;
  116.  
  117.     /* Send the query to Archie */
  118.     DEBUG1("doQueryAndParse: \"%s\"\n",str);
  119.     DEBUG0("calling stringQuery...\n");
  120.     links = stringQuery(appResources.archieHost,str);
  121.     DEBUG0("calling handleProsperoErrors...\n");
  122.     (void)handleProsperoErrors();
  123.     /* If we aborted or had an error, then don't clear the db */
  124.     if (links == NULL ) {
  125.     /* Wasn't an error... */
  126.     if (perrno == PSUCCESS)
  127.         status0("No matches -- Ready.");
  128.     return;
  129.     }
  130.     /* Reset browser to leftmost position */
  131.     resetBrowser();
  132.     /* Empty (and free) previous contents of database */
  133.     clearEntries(db);
  134.     /* Process the results into the database */
  135.     status0("Parsing...");
  136.     DEBUG0("calling parseArchieQueryResults\n");
  137.     switch(appResources.sortType) {
  138.     case GfName:
  139.         num = parseArchieQueryResults(db,links,cmpEntryNames);
  140.         break;
  141.     case GfDate:
  142.         num = parseArchieQueryResults(db,links,cmpEntryDates);
  143.         break;
  144.     case GfWeight:
  145.         num = parseArchieQueryResults(db,links,cmpEntryWeights);
  146.         break;
  147.     }
  148.     /* Display results in browser */
  149.     DEBUG0("calling displayEntries\n");
  150.     displayEntries(db,0);
  151.     status1("Found %d matches -- Ready",(char *)num);
  152.     DEBUG0("doQueryAndParse: done\n");
  153. }
  154.  
  155. /*    -    -    -    -    -    -    -    -    */
  156. /*
  157.  * Returns an unsorted, untranslated list of vlinks for string from host.
  158.  */
  159. VLINK
  160. stringQuery(host,string)
  161. char *host,*string;
  162. {
  163.     VLINK links;        /* Matches returned by server */
  164.     VDIR_ST dir_st;        /* Filled in by get_vdir      */
  165.     PVDIR dir = &dir_st;
  166.     VLINK p,nextp,r;
  167.     int    tmp;
  168.     
  169.     /* initialize Prospero globals from appResources */
  170.     pfs_debug = appResources.debugLevel;
  171.     rdgram_priority = appResources.niceLevel;
  172.     client_dirsrv_timeout = appResources.timeout;
  173.     client_dirsrv_retry = appResources.retries;
  174.  
  175.     /* Initialize Prospero structures */
  176.     perrno = PSUCCESS; *p_err_string = '\0';
  177.     pwarn = PNOWARN; *p_warn_string = '\0';
  178.     vdir_init(dir);
  179.     
  180.     /* Retrieve the list of matches, return error if there was one */
  181. #if defined(MSDOS)
  182.     if ((tmp=get_vdir(host,string,"",dir,
  183.               (long)GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) != 0) {
  184. #else
  185.     if ((tmp=get_vdir(host,string,"",dir,
  186.               GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) != 0) {
  187. # endif
  188.     perrno = tmp;
  189.     return(NULL);
  190.     }
  191.     
  192.     /* Save the links, and clear in dir in case it's used again   */
  193.     links = dir->links; dir->links = NULL;
  194.     
  195.     /* As returned, list is sorted by suffix, and conflicting     */
  196.     /* suffixes appear on a list of "replicas".  We want to       */
  197.     /* create a one-dimensional list sorted by host then filename */
  198.     /* and maybe by some other parameter                          */
  199.     
  200.     /* First flatten the doubly-linked list */
  201.     for (p = links; p != NULL; p = nextp) {
  202.     nextp = p->next;
  203.     if (p->replicas != NULL) {
  204.         p->next = p->replicas;
  205.         p->next->previous = p;
  206.         for (r = p->replicas; r->next != NULL; r = r->next)
  207.         /*EMPTY*/ ;
  208.         r->next = nextp;
  209.         nextp->previous = r;
  210.         p->replicas = NULL;
  211.     }
  212.     }
  213.     perrno = PSUCCESS;
  214.     return(links);
  215. }
  216.  
  217. /*    -    -    -    -    -    -    -    -    */
  218. /*
  219.  * Here take the list of untranslated unsorted links and put them into the
  220.  * database, translating and sorting as needed. The entries are added to
  221.  * make a host-location-file hierarchy as appropriate for the top of the
  222.  * database query for a query. Returns number of entries returned from query.
  223.  * This routine is also used by the routine that reloads a database.
  224.  */
  225. int
  226. parseArchieQueryResults(parent,links,cmp_proc)
  227. DbEntry *parent;
  228. VLINK links;
  229. int (*cmp_proc)();
  230. {
  231.     VLINK vl;
  232.     DbEntry *firstHost,*firstLoc;
  233.     DbEntry *thisHost,*thisLoc,*thisFile;
  234.     char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
  235.     int type;
  236. #ifdef MSDOS
  237.     unsigned long size;
  238. #else
  239.     int size;
  240. #endif
  241.     char *modes,*gt_date,*archie_date;
  242.     int num;
  243.  
  244.     DEBUG0("parseArchieQueryResults: parsing links...\n");
  245.     num = 0;
  246.     firstHost = firstLoc = NULL;
  247.     for (vl=links; vl != NULL; vl = vl->next) {
  248.     parseHostAndFilename(vl,hostname,location,filename);
  249.     parseAttributes(vl,&type,&size,&modes,&archie_date,>_date);
  250.     if (firstHost == NULL) {
  251.         firstHost = thisHost = addEntry(parent,NULL);
  252.         firstLoc = thisLoc = addEntry(firstHost,NULL);
  253.         thisFile = addEntry(firstLoc,NULL);
  254.     } else {
  255.         if ((thisHost=findEntryFromString(parent,hostname)) == NULL)
  256.         thisHost = addEntry(parent,NULL);
  257.         if ((thisLoc=findEntryFromString(thisHost,location)) == NULL)
  258.         thisLoc = addEntry(thisHost,NULL);
  259.         thisFile = addEntry(thisLoc,NULL);
  260.     }
  261.     setEntryData(thisHost,hostname,DB_HOST,0,"","","",NULL);
  262.     setEntryData(thisLoc,location,DB_LOCATION,0,"","","",NULL);
  263.     setEntryData(thisFile,filename,type,size,modes,archie_date,gt_date,vl);
  264.     num += 1;
  265.     }
  266.     DEBUG0("parseArchieQueryResults: sorting entries...\n");
  267.     sortEntriesRecursively(parent,cmp_proc);
  268.     DEBUG1("parseArchieQueryResults: returning %d matches\n",num);
  269.     return(num);
  270. }
  271.  
  272. /*
  273.  * Like parseArchieQueryresults(), but all the entries for the links are
  274.  * added as immediate children of parent, rather than a three-level tree.
  275.  * This is used to expand the browser below some item.
  276.  */
  277. int
  278. parseStringQueryResults(parent,links,cmp_proc)
  279. DbEntry *parent;
  280. VLINK links;
  281. int (*cmp_proc)();
  282. {
  283.     VLINK vl;
  284.     DbEntry *dbp;
  285.     char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
  286.     int type,size;
  287.     char *modes,*gt_date,*archie_date;
  288.     int num;
  289.  
  290.     DEBUG0("parseStringQueryResults: parsing links...\n");
  291.     num = 0;
  292.     for (vl=links; vl != NULL; vl = vl->next) {
  293.     parseHostAndFilename(vl,hostname,location,filename);
  294.     parseAttributes(vl,&type,&size,&modes,&archie_date,>_date);
  295.     dbp = addEntry(parent,NULL);
  296.     setEntryData(dbp,filename,type,size,modes,archie_date,gt_date,vl);
  297.     num += 1;
  298.     }
  299.     DEBUG0("parseStringQueryResults: sortign entries...\n");
  300.     sortEntriesRecursively(parent,cmp_proc);
  301.     DEBUG1("parseStringQueryResults: returning %d matches\n",num);
  302.     return(num);
  303. }
  304.     
  305. /*
  306.  * Fills in hostname, location, and filename with the appropriately-translated
  307.  * and adjusted information from the link vl.
  308.  */
  309. static void
  310. parseHostAndFilename(vl,hostname,location,filename)
  311. VLINK vl;
  312. char *hostname,*location,*filename;
  313. {
  314.     char *slash;
  315.  
  316.     DEBUG3(" input:host=\"%s\"\n       filename=\"%s\"\n       name=\"%s\"\n",
  317.        vl->host,vl->filename,vl->name);
  318.     /* If the link is for an Archie pseudo-directory, adjust names. */
  319.     if (strcmp(vl->type,"DIRECTORY") == 0 &&
  320.     strncmp(vl->filename,"ARCHIE/HOST",11) == 0) {
  321.     strcpy(hostname,vl->filename+12);
  322.     slash = index(hostname,'/');
  323.     if (slash != NULL) {
  324.         strcpy(filename,slash);
  325.         *slash = '\0';
  326.     } else
  327.         strcpy(filename,"/");
  328.     } else {
  329.     /* else just use the names as is */
  330.     strcpy(hostname,vl->host);
  331.     strcpy(filename,vl->filename);
  332.     }
  333.     /* The "location" is the leading part of the pathname */
  334.     strcpy(location,filename);
  335.     slash = rindex(location,'/');
  336.     /* If filename ends with slash, try going back one more slash */
  337.     if (slash && *(slash+1) == '\0')
  338.     slash = (char *)rindex(slash,'/');
  339.     if (slash) {
  340.     strcpy(filename,slash+1);
  341.     *slash = '\0';
  342.     } else
  343.     strcpy(location,"/");
  344.     /* If filename was /foo, then we need to leave the slash there */
  345.     if (*location == '\0')
  346.     strcpy(location,"/");
  347.     DEBUG3(" output:host=\"%s\"\n        location=\"%s\"\n        filename=\"%s\"\n",
  348.        hostname,location,filename);
  349. }
  350.  
  351. /*
  352.  * Fills in *sizep, *modesp, and archie_date with the information in the
  353.  * attribute list of the link vl.
  354.  */
  355. static void
  356. parseAttributes(vl,typep,sizep,modesp,archie_datep,gt_datep)
  357. VLINK vl;
  358. int *typep;
  359. #ifdef MSDOS
  360. unsigned long *sizep;
  361. #else
  362. int *sizep;
  363. #endif
  364. char **modesp,**archie_datep,**gt_datep;
  365. {
  366.     static char date[64];
  367.     PATTRIB ap;
  368.     int  gt_year,gt_mon,gt_day,gt_hour,gt_min;
  369.     struct tm *presenttime;
  370.     long now;
  371.  
  372.     (void)time(&now);
  373.     presenttime = localtime(&now);
  374.     if (strcmp(vl->type,"DIRECTORY") == 0) {
  375.     *typep = DB_DIRECTORY;
  376.     } else {
  377.     *typep = DB_FILE;
  378.     }
  379.     *sizep = 0;
  380.     *modesp = "";
  381.     *archie_datep = "";
  382.     *gt_datep = "";
  383.     gt_year = gt_mon = gt_day = gt_hour = gt_min = 0;
  384.     for (ap = vl->lattrib; ap; ap = ap->next) {
  385.     if (strcmp(ap->aname,"SIZE") == 0) {
  386. #ifdef MSDOS
  387.         sscanf(ap->value.ascii,"%lu",sizep);
  388. #else
  389.         sscanf(ap->value.ascii,"%d",sizep);
  390. #endif
  391.     } else if(strcmp(ap->aname,"UNIX-MODES") == 0) {
  392.         *modesp = ap->value.ascii;
  393.     } else if(strcmp(ap->aname,"LAST-MODIFIED") == 0) {
  394.         *gt_datep = ap->value.ascii;
  395.         sscanf(*gt_datep,"%4d%2d%2d%2d%2d",>_year,
  396.            >_mon, >_day, >_hour, >_min);
  397.         if ((12 * (presenttime->tm_year + 1900 - gt_year) +
  398.          presenttime->tm_mon - gt_mon) > 6)
  399.         sprintf(date,"%s %2d %4d",month_sname(gt_mon),
  400.             gt_day, gt_year);
  401.         else
  402.         sprintf(date,"%s %2d %02d:%02d",month_sname(gt_mon),
  403.             gt_day, gt_hour, gt_min);
  404.         *archie_datep = date;
  405.     }
  406.     }
  407. }
  408.  
  409. /*
  410.  * Pops up alerts depending on perrno and pwarn.
  411.  * Used in several places after calling Archie.
  412.  */
  413. int
  414. handleProsperoErrors()
  415. {
  416.     int err = 0;
  417.  
  418.     /* Error? */
  419.     if (perrno != PSUCCESS) {
  420.     if (p_err_text[perrno]) {
  421.       if (*p_err_string)
  422.         alert2("Prospero error: %.100s - %.100s",p_err_text[perrno],
  423.             p_err_string);
  424.       else
  425.         alert1("Prospero error: %.200s",p_err_text[perrno]);
  426.     } else
  427.         alert1("Prospero error: Undefined error %d (prospero)",(char*)perrno);
  428.     err = 1;
  429.     }
  430.     /* Warning? */
  431.     if (pwarn != PNOWARN) {
  432.         if (*p_warn_string)
  433.             alert2("Prospero warning: %.100s - %.100s",
  434.                    p_warn_text[pwarn], p_warn_string);
  435.         else
  436.             alert1("Prospero warning: %.200s",p_warn_text[pwarn]);
  437.         status0("Ready");
  438.     }
  439.     return(err);
  440. }
  441.